// CompareGraphs.cpp : Defines the entry point for the console application.
//
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <math.h>

#define DELTA_DOUBLE_COMP   0.000001

#define BUF_SIZE 1000
#define SQR(a) ((a)*(a))

#define NUM_ACTORS 4 // 3, 4, 5, 10
#define NUM_EXPTS 4
#define NUM_COSTS 20
#define NUM_BENEFITS 20
#define NUM_DENSITY 3

enum COMPARISON_RESULT
{
    CR_NONE = 0,
    CR_MATCH = 1,
    CR_MISMATCH = 2,
    CR_RESULT_UNKNOWN = 3
};

enum NTWK_STRUCT {  NS_NULL = 0,
                    NS_STAR,
                    NS_SHARED,
                    NS_COMPLETE,
                    NS_NEAR_NULL,
                    NS_NEAR_STAR,
                    NS_NEAR_SHARED,
                    NS_NEAR_COMPLETE,
                    NS_K_PARTITE,
                    NS_K_PARTITE_COMPLETE,
                    NS_TYPE_SIZE
};

int getParamMetrics(char* buf, int& N, int& expt, double& c, double& density, double& delta, NTWK_STRUCT& network, int& k);
NTWK_STRUCT getEnum(int i);
COMPARISON_RESULT getResult( int N, double c, double delta, NTWK_STRUCT network, int k );
COMPARISON_RESULT getResult_u2( int N, double c, double delta, NTWK_STRUCT network, int k );
bool isEqual( double val1, double val2 );


int main(int argc, char* argv[])
{

    char buf[BUF_SIZE];
    double delta, c, density;
    NTWK_STRUCT network;
    int N, expt;
    int k; // 'k' of the k-partition. valid if network is k-partition

    COMPARISON_RESULT result[NUM_ACTORS][NUM_EXPTS][NUM_DENSITY][NUM_COSTS][NUM_BENEFITS];
    double success_rates[NUM_ACTORS][NUM_EXPTS][NUM_DENSITY];

    FILE* fp = fopen( "c:\\temp\\socialNetwork.summary", "r" );

    // while( fp != NULL )
    if( fp != NULL )
    for( int v=0; v<NUM_ACTORS; v++ )
    for( int w=0; w<NUM_EXPTS; w++ )
    for( int x=0; x<NUM_DENSITY; x++ )
    for( int y=0; y<NUM_COSTS; y++ )
    for( int z=0; z<NUM_BENEFITS; z++ )
    {
        fgets( buf, BUF_SIZE, fp );
        getParamMetrics(buf, N, expt, c, delta, density, network, k);

        assert( isEqual(expt, w+1) );
        assert( isEqual(density, x*0.35) );        
        assert( isEqual(c, y*0.05) );
        assert( isEqual(delta, z*0.05) );

        COMPARISON_RESULT comp_result = getResult_u2( N, c, delta, network, k );
        result[v][w][x][y][z] = comp_result;
    }


    for( int v=0; v<NUM_ACTORS; v++ )
    for( int w=0; w<NUM_EXPTS; w++ )
    for( int x=0; x<NUM_DENSITY; x++ )
    {
        int match_count = 0;

        for( int y=0; y<NUM_COSTS; y++ )
        for( int z=0; z<NUM_BENEFITS; z++ )
            if( result[v][w][x][y][z] == CR_MATCH )
                match_count++;

        success_rates[v][w][x] = ((double)match_count) / (NUM_COSTS * NUM_BENEFITS);
    }

    // print
    printf("Success rates\n");
    for( int v=0; v<NUM_ACTORS; v++ )
    for( int w=0; w<NUM_EXPTS; w++ )
    for( int x=0; x<NUM_DENSITY; x++ )
    {
        int numActors;

        if( v <= 2 )  numActors = v+3;
        else if (v == 3) numActors = 10;
        else assert(false);

        printf("%d\t%d\t%0.2f\t%0.2lf\n", numActors, w+1, x*0.35, success_rates[v][w][x]);
    }

    fclose(fp);
	return 0;
}

int getParamMetrics(char* buf, int& N, int& expt, double& c, double& density, double& delta, NTWK_STRUCT& network, int& k)
{
    char* pch = strtok(buf, " "); // rand seed
    N = atoi( strtok(NULL, " ") );
    expt = atoi( strtok(NULL, " ") );
    strtok(NULL, " "); // repeat
    c = atof( strtok(NULL, " ") );
    density = atof( strtok(NULL, " ") );
    delta = atof( strtok(NULL, " ") );
    strtok(NULL, " "); // mean acts
    strtok(NULL, " "); // mean iterations
    strtok(NULL, " "); // mean utility


    int histogram[NS_TYPE_SIZE];
    int arrIndex = 0;

    histogram[arrIndex++] = atoi( strtok(NULL, " ") );
    histogram[arrIndex++] = atoi( strtok(NULL, " ") );
    histogram[arrIndex++] = atoi( strtok(NULL, " ") );
    histogram[arrIndex++] = atoi( strtok(NULL, " ") );
    histogram[arrIndex++] = atoi( strtok(NULL, " ") );
    histogram[arrIndex++] = atoi( strtok(NULL, " ") );
    histogram[arrIndex++] = atoi( strtok(NULL, " ") );
    histogram[arrIndex++] = atoi( strtok(NULL, " ") );
    histogram[arrIndex++] = atoi( strtok(NULL, " ") );
    histogram[arrIndex++] = atoi( strtok(NULL, " ") );

    k = atoi( strtok(NULL, " ") );

    int maxVal = -1;
    int maxIndex = -1;
    for( int i=0; i<NS_TYPE_SIZE; i++ )
    {
        if( histogram[i] > maxVal )
        {
            maxVal = histogram[i];
            maxIndex = i;
        }
    }

    network = getEnum(maxIndex);

    return 0;
}

NTWK_STRUCT getEnum(int i)
{
    switch(i)
    {
    case 0: return NS_NULL;
    case 1: return NS_STAR;
    case 2: return NS_SHARED;
    case 3: return NS_COMPLETE;
    case 4: return NS_NEAR_NULL;
    case 5: return NS_NEAR_STAR;
    case 6: return NS_NEAR_SHARED;
    case 7: return NS_NEAR_COMPLETE;
    case 8: return NS_K_PARTITE;
    case 9: return NS_K_PARTITE_COMPLETE;
    default:
        assert(false);
        return NS_TYPE_SIZE;
    }
}

COMPARISON_RESULT getResult( int N, double c, double delta, NTWK_STRUCT network, int k )
{
    if( (delta > c) && ((delta-c)>SQR(delta)) )
    {
        if( network == NS_COMPLETE )
            return CR_MATCH;

        if( (network == NS_SHARED) && (N == 3) ) // for 3 actors, shared is same as complete
            return CR_MATCH;
    }

    if( (delta > c) && ((delta-c)<SQR(delta)) )
    {
        if( network == NS_COMPLETE )
            return CR_MATCH;

        if( (network == NS_SHARED) && (N == 3) ) // for 3 actors, shared is same as complete
            return CR_MATCH;
    }

    if( (delta > c) && ((delta-c)<SQR(delta)) )
    {
        if( ( network == NS_K_PARTITE_COMPLETE ) && (k == 2) && ((N%2) == 0) )
        {
            double lhs = (delta-c)/SQR(delta);
            double rhs = 2.0/((N/2)+1); 

            if( rhs <= lhs )
                return CR_MATCH;
        }
    }

    if( delta > c )
    {
        if( ( network == NS_K_PARTITE_COMPLETE ) && (k >= 3) && ((N%k) == 0) )
            return CR_MATCH;
    }

    /////
    if( delta > c )
    {
        if( (network == NS_K_PARTITE_COMPLETE) && (N%k) == 0 )
        {
            int a = N/k;
            int di = (k-1)*a;
            double psi = 2.0/(di * (SQR(di) - 1));
            double delta_si_add = psi * ( ((k-1)*SQR(a))-((k-1)*a) );

            if( (delta-c) <= (delta_si_add * SQR(delta)) )
                return CR_MATCH;
        }
    }

    if( delta == c )
    {
        if( (network == NS_SHARED) || (network == NS_COMPLETE) || ((network == NS_K_PARTITE_COMPLETE) &&(k==2)) )
            return CR_MATCH;
    }

    if( delta == c )
    {
        if( (network == NS_K_PARTITE_COMPLETE) &&(k>=3) && ((N%k) == 0) )
            return CR_MATCH;
    }

    if( (delta < c) && ((SQR(delta) + 2*(delta-c))<0) )
    {
        if( network == NS_NULL )
            return CR_MATCH;
    }

    if( (delta < c) && ((SQR(delta) + 2*(delta-c))>0) )
    {
        if( network == NS_SHARED )
            return CR_MATCH;

        if( (network == NS_K_PARTITE_COMPLETE) && (k==2) && ((N%2) == 0) && (N>=4) )
            return CR_MATCH;
    }

    return CR_MISMATCH;
}

bool isEqual( double val1, double val2 )
{
    if( fabs(val1 - val2) < DELTA_DOUBLE_COMP )
        return true;

    return false;
}

COMPARISON_RESULT getResult_u2( int N, double c, double delta, NTWK_STRUCT network, int k )
{
    if( (delta > c) && ((delta-c)>SQR(delta)) )
    {
        if( network == NS_COMPLETE )
            return CR_MATCH;

        if( (network == NS_SHARED) && (N == 3) ) // for 3 actors, shared is same as complete
            return CR_MATCH;
    }

    if( (delta > c) && ((delta-c)<SQR(delta)) )
    {
        if( network == NS_COMPLETE )
            return CR_MATCH;

        if( (network == NS_SHARED) && (N == 3) ) // for 3 actors, shared is same as complete
            return CR_MATCH;

        if( (network == NS_K_PARTITE_COMPLETE) && ((N%2) == 0) && (k == 2))
            return CR_MATCH;
    }

    if( delta == c )
    {
        if( (network == NS_SHARED) || (network == NS_COMPLETE) || (network == NS_NULL) || ((network == NS_K_PARTITE_COMPLETE) &&(k==2)) )
            return CR_MATCH;
    }

    if( delta == c )
    {
        if( ( network == NS_K_PARTITE_COMPLETE ) && (k >= 3) && ((N%k) == 0) )
            return CR_MATCH;
    }

    if( delta < c )
    {
        if( network == NS_NULL )
            return CR_MATCH;
    }

    if( (delta < c) && (2 >= ((c-delta)/SQR(delta))) && (((c-delta)/SQR(delta)) >= 1) )
    {
        if( network == NS_SHARED )
            return CR_MATCH;
    }

    if( (delta < c) && (SQR(delta) >= (c-delta)) )
    {
        if( (network == NS_K_PARTITE_COMPLETE) && (k==2) && ((N%2) == 0) )
            return CR_MATCH;
    }

    if( delta < c )
    {
        if( ( network == NS_K_PARTITE_COMPLETE ) && (k >= 3) && ((N%k) == 0) )
            return CR_MATCH;
    }

    if( (delta-c) <= ((2.0/3.0) * SQR(delta)) )
    {
        if( ( network == NS_K_PARTITE_COMPLETE ) && (k == 3) && ((N%k) == 0) )
            return CR_MATCH;
    }

    return CR_MISMATCH;
}

